package com.warm.common.util;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.apache.commons.lang3.StringUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description 为链接生成二维码
 * @Author warmchuang
 * @Date 2021/1/29 9:42
 */
public class QRCodeUtil {

    private static final String CHARSET = "utf-8";
    private static final String FORMAT_NAME = "JPG";

    private static final int QRCODE_SIZE = 200;
    private static final int LOG_WIDTH = 60;
    private static final int LOG_HEIGHT = 60;

    /**
     * 生成二维码(内嵌LOGO)
     *
     * @param content 内容
     * @param logPath LOGO地址
     * @param outPath 存放目录
     * @throws Exception
     */
    public static String encode(String content, String filename, String logPath, String outPath){
        try {
            BufferedImage image = createImage(content);
            if (StringUtils.isNotBlank(logPath)) {
                // 插入LOG图片
                insertImage(image, logPath);
            }
            mkdirs(outPath);
            filename = filename + "." + FORMAT_NAME;
            ImageIO.write(image, FORMAT_NAME, new File(outPath + "/" + filename));
            return filename;
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("生成二维码失败");
        }
        return null;
    }

    public static String encode(String content, String filename, String outPath){
        return encode(content, filename,null, outPath);
    }

    /**
     * 获取流
     * @param content
     * @param logPath
     * @return
     */
    public static InputStream encode(String content, String logPath){
        ByteArrayOutputStream os = null;
        InputStream in = null;
        try {
            BufferedImage image = createImage(content);
            if (StringUtils.isNotBlank(logPath)) {
                // 插入LOG图片
                insertImage(image, logPath);
            }
            os = new ByteArrayOutputStream();
            ImageIO.write(image, FORMAT_NAME, os);
            in = new ByteArrayInputStream(os.toByteArray());
            return in;
        } catch (IOException e) {
            System.out.println("生成二维码失败");
        } finally {
            closeStream(os, in);
        }
        return in;
    }

    /**
     * 解析二维码
     *
     * @param file 二维码图片
     * @return
     * @throws Exception
     */
    public static String decode(File file) {
        try {
            BufferedImage image;
            image = ImageIO.read(file);
            if (image == null) {
                return null;
            }
            BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
            Result result;
            HashMap<DecodeHintType, Object> hints = new HashMap<DecodeHintType, Object>();
            hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
            result = new MultiFormatReader().decode(bitmap, hints);
            String resultStr = result.getText();
            return resultStr;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("解码失败");
        }
        return null;
    }

    /**
     * 解析二维码
     *
     * @param path 二维码图片地址
     * @return
     * @throws Exception
     */
    public static String decode(String path){
        return decode(new File(path));
    }


    private static BufferedImage createImage(String content) {
        try {
            Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
            hints.put(EncodeHintType.MARGIN, 1);

            BitMatrix bitMatrix = null;
            bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints);
            int width = bitMatrix.getWidth();
            int height = bitMatrix.getHeight();
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
                }
            }
            return image;
        } catch (WriterException e) {
            System.out.println("创建图片失败");
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 插入LOGO
     *
     * @param source 二维码图片
     * @param imgPath LOGO图片地址
     * @throws Exception
     */
    private static void insertImage(BufferedImage source, String imgPath) {

        try {
            File file = new File(imgPath);
            if (!file.exists()) {
                System.out.println("图片不存在");
                return;
            }
            Image src = null;
            src = ImageIO.read(new File(imgPath));
            int width = src.getWidth(null);
            int height = src.getHeight(null);
            if(width > LOG_WIDTH || height > LOG_HEIGHT){
                if (width > LOG_WIDTH) {
                    width = LOG_WIDTH;
                }
                if (height > LOG_HEIGHT) {
                    height = LOG_HEIGHT;
                }
                Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
                BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                Graphics g = tag.getGraphics();
                g.drawImage(image, 0, 0, null); // 绘制缩小后的图
                g.dispose();
                src = image;
            }
            // 插入LOGO
            Graphics2D graph = source.createGraphics();
            int x = (QRCODE_SIZE - width) / 2;
            int y = (QRCODE_SIZE - height) / 2;
            graph.drawImage(src, x, y, width, height, null);
            Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
            graph.setStroke(new BasicStroke(3f));
            graph.draw(shape);
            graph.dispose();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 当文件夹不存在时，mkdirs会自动创建多层目录，区别于mkdir．(mkdir如果父目录不存在则会抛出异常)
     * @date 2013-12-11 上午10:16:36
     * @param destPath 存放目录
     */
    public static void mkdirs(String destPath) {
        File file = new File(destPath);
        //当文件夹不存在时，mkdirs会自动创建多层目录，区别于mkdir．(mkdir如果父目录不存在则会抛出异常)
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

    private static void closeStream(ByteArrayOutputStream os, InputStream in){
        if(os != null){
            try {
                os.close();
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
        if(in != null){
            try {
                in.close();
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }

    public static void main(String[] args) {
        String text = "warmchuang, tomorrow will be better!"; // 这里设置自定义网站url
        String logoPath = "D:\\head.jpeg"; // 二维码增加logo
        String destPath = "D:\\";
        System.out.println(encode(text, "qrImg", logoPath, destPath));
        //System.out.println(decode("D:\\qrImg.jpg")); // 图片解码
    }
}
